home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The CICA Windows Explosion!
/
The CICA Windows Explosion! - Disc 2.iso
/
misc
/
btngo.zip
/
BTNGOC.ZIP
/
LONCH.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1993-09-28
|
32KB
|
750 lines
// DEBUG_SCREENS for message-box progress indicators
// FAKE_LAUNCHES for message boxes instead of actual launches
// SHOW_LAUNCHDATA for quick display just before prog launch -- works only if FAKE_LAUNCHES *not* specified
// CHANGE_DIR to change directory to entry's default before launch attempted
#include<windows.h>
#include<commdlg.h>
#include"wstring.hpp"
#include"itemdata.hpp"
#include"resource.h"
#include"ini.hpp"
#include<string.h>
#include<ctype.h>
#ifndef FAKE_LAUNCHES
#include<direct.h>
#endif
#define IDM_GETSTARTED 1
#define IDM_ABOUT 1001
#define IDM_HELP 1002
#define IDM_ONTOP 1003
#define IDM_MYSYSCOMMANDS 1010
#define BUTTON_WIDTH (icon_width+5)
IniFile ini;
GroupFile gf;
#ifdef DEBUG_SCREENS
WinMessageString screen;
#endif
WinMessageString errscreen;
const int SCRATCH=256;
unsigned int winver; // windows version
char scratch[SCRATCH+1];
static char WindowTitle[256];
static char szFile[256]; // filename for .GRP file
static HWND main_hwnd=NULL;
static HINSTANCE main_hinst=NULL;
static char AppTitle[]="ButtonGo";
static char AppClassName[]="ButtonGoDeurbrouckClass";
static char copyright[]=
"BTNGO.EXE 1.0\n"
"Program Launching Utility\n"
"Copyright ⌐ 1993 John Deurbrouck\n\n"
"First published in PC Magazine September 28, 1993\n";
static char helpstring[]=
"BTNGO conveniently displays the icons from any Program Manager group "
"and allows you to launch them with a single mouse click.\n\n"
"If started with a .GRP file specified on the command line, BTNGO can operate under "
"Windows 3.0 and later. Otherwise, BTNGO requires COMMDLG.DLL to run under 3.0.\n\n"
"See PC Magazine, September 28, 1993 (Vol. 12 No. 15) for more details. Support is also available "
"on ZiffNet. From Compuserve, GO ZNT:UTILFORUM.";
static char too_many_icons[]=
"The group you have loaded has too many icons to display, "
"so some of your icons may not be visible. "
"No damage has occurred, and you may use the icons you can see.\n\n"
"You can fix this by removing less-important items from the group, or by "
"creating another group file and moving some icons from this group "
"to the new one.";
static LPSTR command_line_pointer;
static HMENU gm=NULL; // system menu for main window
static HBITMAP hbmUp=NULL,hbmDown=NULL,hbmNow=NULL; // for painting the main window
static unsigned int max_index_added=0;
static int show_parameter; // for call to ShowWindow, parm passed into WinMain
static int actual_buttons=0; // number buttons on button bar
static int icon_height,icon_width,bitmap_width,bitmap_height;
static int mouse_down=0,mouse_button_number=-1,ok_to_launch; // used to drive mouse handling
static int should_save_position_data=0,got_position_data,best_ontop=1,best_x,best_y; // used for .INI file handling
void GetFilenameFromCmdLine(LPSTR cmdline,char *winpath,char *filename);
long FAR PASCAL __export MainWndProc(HWND,UINT,UINT,LONG);
int GetFileDataLoaded(LPSTR cmdline);
int CreateBitmaps(void);
int button_mouse_is_in(LONG lParam);
void restore_mouse_normalcy(void);
void get_right_bitmap(HDC hdc);
#ifdef FAKE_LAUNCHES
char *show_exe_data(int offset);
#else
void start_program(int offset);
#endif
int PASCAL WinMain(HINSTANCE hinstCurrent,HINSTANCE hinstPrevious,LPSTR lpszCmdLine,int nCmdShow){
if(!hinstPrevious){
WNDCLASS wc;
wc.style=CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS;
wc.lpfnWndProc=MainWndProc;
wc.cbClsExtra=0;
wc.cbWndExtra=0;
wc.hInstance=hinstCurrent;
wc.hIcon=LoadIcon(hinstCurrent,MAKEINTRESOURCE(IDI_APPICON));
wc.hCursor=LoadCursor(NULL,IDC_ARROW);
wc.hbrBackground=NULL;
wc.lpszMenuName=NULL;
wc.lpszClassName=AppClassName;
RegisterClass(&wc);
}
{
DWORD ver=GetVersion();
winver=LOBYTE(LOWORD(ver));
winver<<=8;
winver|=HIBYTE(LOWORD(ver));
}
command_line_pointer=lpszCmdLine;
main_hinst=hinstCurrent;
show_parameter=nCmdShow;
ini.set_instance(hinstCurrent);
main_hwnd=CreateWindow(AppClassName,AppTitle,
WS_OVERLAPPED|WS_SYSMENU|WS_MINIMIZEBOX,
CW_USEDEFAULT,CW_USEDEFAULT, // X,Y coords
CW_USEDEFAULT,CW_USEDEFAULT, // x,y extents
HWND_DESKTOP,NULL,hinstCurrent,NULL);
#ifdef DEBUG_SCREENS
screen.SetHwndParent(main_hwnd);
#endif
errscreen.SetHwndParent(main_hwnd);
MSG msg;
while(GetMessage(&msg,NULL,0,0)){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
static void GetFilenameFromCmdLine(LPSTR cmdline,char *winpath,char *filename){
LPSTR string_start;
int got_pathchars=0,got_goodchars=0,got_whitespace=0;
if(cmdline==NULL)return;
while(*cmdline){ // scan, find filename start, look for '\\' and ':'
if(isgraph(*cmdline)){
if(got_whitespace){
errscreen<<"Too many command line arguments";
errscreen.show();
return;
}
if(!got_goodchars){
got_goodchars=1;
string_start=cmdline;
}
if(*cmdline=='\\'||*cmdline==':')got_pathchars=1;
if(*cmdline=='*'||*cmdline=='?'){
errscreen<<"Can't use wildcards in command line arguments";
errscreen.show();
return;
}
}
else{
if(got_goodchars)got_whitespace=1;
}
cmdline++;
}
if(!got_goodchars)return; // no filename
if(!got_pathchars){ // insert Windows dir, normal place for .GRP
lstrcpy(filename,winpath);
cmdline=filename;
while(*cmdline)cmdline++;
if(cmdline[-1]!='\\'){*cmdline++='\\';*cmdline=0;}
lstrcat(filename,string_start);
}
else lstrcpy(filename,string_start);
// now scan off any whitespace at end of filename
cmdline=filename;
while(*cmdline)cmdline++;
cmdline--;
while(!isgraph(*cmdline))*cmdline--=0;
}
long FAR PASCAL __export MainWndProc(HWND hwnd,UINT message,UINT wParam,LONG lParam){
switch(message){
case WM_CREATE:
PostMessage(hwnd,WM_COMMAND,IDM_GETSTARTED,0L);
return 0;
case WM_COMMAND:
switch(wParam){
case IDM_GETSTARTED:
gm=GetSystemMenu(main_hwnd,FALSE);
DeleteMenu(gm,SC_SIZE,MF_BYCOMMAND);
DeleteMenu(gm,SC_MAXIMIZE,MF_BYCOMMAND);
AppendMenu(gm,MF_SEPARATOR,0,NULL);
if(winver>=0x30A)AppendMenu(gm,MF_STRING,IDM_ONTOP,"Always on Top");
AppendMenu(gm,MF_STRING,IDM_ABOUT,"About...");
AppendMenu(gm,MF_STRING,IDM_HELP,"Help...");
if(!GetFileDataLoaded(command_line_pointer)||
!gf.get_icon_dimensions(icon_height,icon_width)||
!CreateBitmaps()){
PostMessage(hwnd,WM_DESTROY,0,0L);
return 0;
}
if(gf.get_group_name()!=NULL){
wsprintf(WindowTitle,"%s - %s",(LPSTR)AppTitle,gf.get_group_name());
}
else lstrcpy(WindowTitle,AppTitle);
gf.done_with_bitmaps();
SetWindowText(hwnd,WindowTitle);
should_save_position_data=1;
got_position_data=ini.get_screen_numbers(szFile,best_x,best_y,best_ontop);
if(winver>=0x30A&&best_ontop)PostMessage(hwnd,WM_SYSCOMMAND,IDM_ONTOP,0L);
int window_width=GetSystemMetrics(SM_CXBORDER)*2+bitmap_width;
int window_height=GetSystemMetrics(SM_CYCAPTION)+bitmap_height+GetSystemMetrics(SM_CYBORDER);
/*
ok, someone changing from 1024x768 to 800x600 drivers might 'lose' the
window so let's be sure the window's at least partially onscreen.
if at least one pixel of the caption area is onscreen, the window
can be grabbed and moved, so let's check for that
*/
if(got_position_data)for(;;){
got_position_data=0; // so can break on errors
int capt_left=best_x+GetSystemMetrics(SM_CXBORDER)+GetSystemMetrics(SM_CXSIZE)+2;
int capt_right=best_x+window_width-GetSystemMetrics(SM_CXSIZE)-2;
int x_size=GetSystemMetrics(SM_CXSCREEN);
if(!(capt_left<0&&capt_right>=x_size)){ // ok, straddles screen
if(capt_right<0)break;
if(capt_left>=x_size)break;
}
int capt_top=best_y+GetSystemMetrics(SM_CYBORDER)+2;
int capt_bottom=best_y+GetSystemMetrics(SM_CYCAPTION)-2;
int y_size=GetSystemMetrics(SM_CYSCREEN);
if(capt_top>=y_size)break;
if(capt_bottom<0)break;
got_position_data=1;
break;
}
if(got_position_data){
SetWindowPos(hwnd,0,best_x,best_y,
window_width,window_height,
SWP_NOACTIVATE|SWP_NOZORDER);
}
else{
SetWindowPos(hwnd,0,0,0,
window_width,window_height,
SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
}
int window_is_truncated=0;
{
RECT temprect;
GetWindowRect(hwnd,&temprect);
if((temprect.right-temprect.left)!=window_width){
window_is_truncated=1;
}
}
ShowWindow(hwnd,show_parameter);
UpdateWindow(hwnd);
if(window_is_truncated){
MessageBox(hwnd,too_many_icons,"Window Creation Error",MB_OK);
}
return 0;
}
break;
case WM_SYSCOMMAND:
if(wParam>=IDM_MYSYSCOMMANDS&&wParam<=(IDM_MYSYSCOMMANDS+max_index_added)){
#ifdef FAKE_LAUNCHES
MessageBox(hwnd,show_exe_data(wParam-IDM_MYSYSCOMMANDS),"Doing a command",MB_OK|MB_ICONINFORMATION);
#else
start_program(wParam-IDM_MYSYSCOMMANDS);
#endif
return 0;
}
else switch(wParam){
case IDM_ABOUT:
MessageBox(hwnd,copyright,"About ButtonGo",MB_OK|MB_ICONINFORMATION);
return 0;
case IDM_HELP:
MessageBox(hwnd,helpstring,"ButtonGo Help",MB_OK|MB_ICONINFORMATION);
return 0;
case IDM_ONTOP:
if(MF_CHECKED&GetMenuState(gm,IDM_ONTOP,MF_BYCOMMAND)){
CheckMenuItem(gm,IDM_ONTOP,MF_BYCOMMAND|MF_UNCHECKED);
SetWindowPos(hwnd,HWND_NOTOPMOST,0,0,0,0,SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE);
}
else{
CheckMenuItem(gm,IDM_ONTOP,MF_BYCOMMAND|MF_CHECKED);
SetWindowPos(hwnd,HWND_TOPMOST,0,0,0,0,SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE);
}
return 0;
}
break;
case WM_LBUTTONDOWN:
{
int b=button_mouse_is_in(lParam);
if(b!=-1){
mouse_button_number=b;
wsprintf(scratch,"%s (%s)",(LPSTR)gf.get_item_name(b),(LPSTR)gf.get_item_command_nopath(b));
SetWindowText(hwnd,scratch);
mouse_down=1;
ok_to_launch=1;
InvalidateRect(hwnd,NULL,FALSE);
UpdateWindow(hwnd);
SetCapture(hwnd);
return 0;
}
}
break;
case WM_CANCELMODE:
if(mouse_down){
restore_mouse_normalcy();
return 0;
}
break;
case WM_MOUSEMOVE:
if(mouse_down){
int b=button_mouse_is_in(lParam);
if(b!=mouse_button_number){
ok_to_launch=0;
mouse_button_number=b;
if(b!=-1){
wsprintf(scratch,"%s (%s)",(LPSTR)gf.get_item_name(b),(LPSTR)gf.get_item_command_nopath(b));
SetWindowText(hwnd,scratch);
}
else{
SetWindowText(hwnd,WindowTitle);
}
InvalidateRect(hwnd,NULL,FALSE);
UpdateWindow(hwnd);
}
return 0;
}
break;
case WM_LBUTTONUP:
if(mouse_down){
int b=button_mouse_is_in(lParam),its_a_go=0;
if(ok_to_launch&&b==mouse_button_number){
its_a_go=1;
}
restore_mouse_normalcy();
if(its_a_go){
#ifdef FAKE_LAUNCHES
MessageBox(hwnd,show_exe_data(b),"Mousing a command",MB_OK|MB_ICONINFORMATION);
#else
start_program(b);
#endif
}
return 0;
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc=BeginPaint(hwnd,&ps);
if(hdc!=NULL){
HDC hdcmem=CreateCompatibleDC(hdc);
if(hdcmem!=NULL){
HBITMAP hbmOld=SelectObject(hdcmem,hbmNow);
get_right_bitmap(hdcmem);
BitBlt(hdc,0,0,bitmap_width,bitmap_height,hdcmem,0,0,SRCCOPY);
SelectObject(hdcmem,hbmOld);
DeleteDC(hdcmem);
}
}
EndPaint(hwnd,&ps);
}
return 0;
case WM_DESTROY:
if(hbmUp !=NULL){DeleteObject(hbmUp );hbmUp =NULL;}
if(hbmDown!=NULL){DeleteObject(hbmDown);hbmDown=NULL;}
if(hbmNow !=NULL){DeleteObject(hbmNow );hbmNow =NULL;}
if(should_save_position_data){
ini.write_screen_numbers(szFile,hwnd,MF_CHECKED&GetMenuState(gm,IDM_ONTOP,MF_BYCOMMAND)?1:0);
}
PostQuitMessage(0);
return 0;
case WM_ENDSESSION:
if(wParam&&should_save_position_data){
ini.write_screen_numbers(szFile,hwnd,MF_CHECKED&GetMenuState(gm,IDM_ONTOP,MF_BYCOMMAND)?1:0);
}
else break;
return 0;
}
return DefWindowProc(hwnd,message,wParam,lParam);
}
int GetFileDataLoaded(LPSTR lpszCmdLine){
OPENFILENAME ofn;
char szDirName[256];
GetWindowsDirectory(szDirName,sizeof(szDirName));
szFile[0]=0;
GetFilenameFromCmdLine(lpszCmdLine,szDirName,szFile);
if(szFile[0]==0){
memset(&ofn,0,sizeof(ofn));
ofn.lStructSize=sizeof(ofn);
ofn.hwndOwner=main_hwnd;
ofn.lpstrFilter="Group Files\0*.GRP\0";
ofn.nFilterIndex=1;
ofn.lpstrFile=szFile;
ofn.nMaxFile=sizeof(szFile);
ofn.lpstrInitialDir=szDirName;
ofn.lpstrTitle="Choose .GRP file for ButtonGo";
ofn.Flags=OFN_PATHMUSTEXIST|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY;
ofn.lpstrDefExt="GRP";
// let's make sure COMMDLG.DLL is here so unfriendly system message doesn't show up
// on GetOpenFileName() call in Win 3.0
// doing LoadLibrary()/GetProcAddress() shuffle to avoid needing COMMDLG.DLL just to load
int got_commdlg=0;
UINT old_sem=SetErrorMode(SEM_NOOPENFILEERRORBOX);
HINSTANCE h=LoadLibrary("COMMDLG.DLL");
if(h>=HINSTANCE_ERROR){ // ok the DLL is there
BOOL(WINAPI*lpGetOpenFileName)(OPENFILENAME FAR*)=(BOOL(WINAPI*)(OPENFILENAME FAR*))GetProcAddress(h,"GetOpenFileName");
if(lpGetOpenFileName!=NULL){
got_commdlg=1;
if(!(*lpGetOpenFileName)(&ofn)){
FreeLibrary(h);
SetErrorMode(old_sem);
return NULL; // user canceled, so bail out...
}
}
FreeLibrary(h);
}
SetErrorMode(old_sem);
if(!got_commdlg){
errscreen<<"COMMDLG.DLL should be in your WINDOWS\\SYSTEM directory\n\n";
errscreen<<"Until you get that file installed, you'll have to specify a .GRP ";
errscreen<<"filename on BtnGo's command line";
errscreen.show("Quitting");
return NULL;
}
}
#ifdef DEBUG_SCREENS
screen<<"File is \""<<szFile<<"\"\n";
#endif
{ // get to all caps so .INI file works right (same every time even if typed)
char *cp=szFile;
while(*cp){
*cp=toupper((int)*cp);
cp++;
}
}
gf.set_filename(szFile);
if(!gf.openfile()){
errscreen<<"File is "<<szFile<<"\n"<<"Could not open file\n";
errscreen.show();
return NULL;
}
gf.readheader();
#ifdef DEBUG_SCREENS
screen<<"header read was "<<(gf.error()?"not ":"")<<"successful\n";
screen<<"there are "<<gf.itemsleft()<<" items to process\n";
#endif
int added_some=0;
for(int x=0;x<gf.itemsleft();x++){
if(gf.error()){
errscreen<<"aborting due to error\n";
errscreen.show();
break;
}
if(gf.showitem(x)){
actual_buttons++;
char __far *ptr=gf.get_item_name(x);
while(ptr!=NULL&&isspace(*ptr))ptr++;
if(ptr!=NULL&&*ptr){ // don't add to system menu if name was all spaces
if(!(added_some%9))AppendMenu(gm,MF_MENUBARBREAK,0,NULL);
added_some++;
AppendMenu(gm,MF_STRING,IDM_MYSYSCOMMANDS+x,ptr);
max_index_added=max_index_added>(unsigned int)x?max_index_added:(unsigned int)x;
}
}
}
#ifdef DEBUG_SCREENS
screen.show("All Done");
#endif
return 1;
}
int CreateBitmaps(void){
/*
This function creates a set of three bitmaps. The first bitmap, the handle to which is
called hbmUp, is the bitmap that show all the buttons in their up (normal) state.
The second, hbmDown, shows all the buttons in their down state. The last, hbmNow, is
the *current* picture, which is normally all up (a copy of hbmUp) but may include
exactly one button from hbmDown.
The bitmaps are created to fit exactly into the client area of the main window.
So though the main window has NULL for hbrBackground, the area should look fine due
to WM_PAINT always repainting the entire thing. The lack of erase should reduce flicker.
*/
int width,height=icon_height+5,retval=0;
HDC hdc=NULL,memhdc=NULL,icondc=NULL,bwdc=NULL;
HBRUSH hbrFace=NULL,hbrOld=NULL;
HPEN hpFace=NULL,hpHighlight=NULL,hpShadow=NULL,hpBlack=NULL,hpOld=NULL;
HBITMAP hbmOld=NULL;
{
int temp=GetSystemMetrics(SM_CXMIN); // window can't be arbitrarily small
width=actual_buttons*BUTTON_WIDTH;
width=width>temp?width:temp;
}
bitmap_width=width;
bitmap_height=height;
// create bitmaps
hbmUp=CreateBitmap(width,height,gf.get_icon_planes(),gf.get_icon_pixelbits(),NULL);
hbmDown=CreateBitmap(width,height,gf.get_icon_planes(),gf.get_icon_pixelbits(),NULL);
hbmNow=CreateBitmap(width,height,gf.get_icon_planes(),gf.get_icon_pixelbits(),NULL);
if(hbmUp==NULL||hbmDown==NULL||hbmNow==NULL)return 0;
// create display context
if((hdc=CreateDC("DISPLAY",NULL,NULL,NULL))==NULL)goto bailout;
// create compatible DC and select 'up' bitmap
if(NULL==(memhdc=CreateCompatibleDC(hdc)))goto bailout;
hbmOld=SelectObject(memhdc,hbmUp);
// create DC for icon
icondc=CreateCompatibleDC(hdc);
if(icondc==NULL)goto bailout;
// create brush for button faces and select it
if(NULL==(hbrFace =CreateSolidBrush(GetSysColor(COLOR_BTNFACE ))))goto bailout;
hbrOld=SelectObject(memhdc,hbrFace);
// create pens for black, button faces, edges, select face color
if(NULL==(hpBlack=GetStockObject(BLACK_PEN)))goto bailout;
if(NULL==(hpFace =CreatePen(PS_SOLID,1,GetSysColor(COLOR_BTNFACE ))))goto bailout;
if(winver>=0x30A){
if(NULL==(hpHighlight=CreatePen(PS_SOLID,1,GetSysColor(COLOR_BTNHIGHLIGHT))))goto bailout;
}
else{
if(NULL==(hpHighlight=CreatePen(PS_SOLID,1,RGB(255,255,255))))goto bailout;
}
if(NULL==(hpShadow =CreatePen(PS_SOLID,1,GetSysColor(COLOR_BTNSHADOW ))))goto bailout;
hpOld=SelectObject(memhdc,hpFace);
Rectangle(memhdc,0,0,width,height); // faces, up map
{ // button edges, up map
int f_ofset,x_offset,x_size,y_size;
for(f_ofset=0,x_offset=0;f_ofset<actual_buttons;f_ofset++,x_offset+=(5+icon_width)){
int oldstretchmode=SetStretchBltMode(memhdc,STRETCH_DELETESCANS);
{ // get AND data
HBITMAP x=gf.get_fill_item_and_bitmap(f_ofset,x_size,y_size);
if(x!=NULL){
x=SelectObject(icondc,x); // save old one...
StretchBlt(memhdc,x_offset+2,2,icon_width,icon_height,icondc,0,0,x_size,y_size,SRCAND);
x=SelectObject(icondc,x); // get new one back
DeleteObject(x); // and delete it
}
}
{ // get XOR data
HBITMAP x=gf.get_fill_item_xor_bitmap(f_ofset,x_size,y_size);
if(x!=NULL){
x=SelectObject(icondc,x); // save old one...
StretchBlt(memhdc,x_offset+2,2,icon_width,icon_height,icondc,0,0,x_size,y_size,SRCINVERT);
x=SelectObject(icondc,x); // get new one back
DeleteObject(x); // and delete it
}
}
SetStretchBltMode(memhdc,oldstretchmode);
SelectObject(memhdc,hpBlack); // draw black lines
MoveTo(memhdc,x_offset ,1);
LineTo(memhdc,x_offset ,icon_height+4);
MoveTo(memhdc,x_offset+icon_width+4 ,1);
LineTo(memhdc,x_offset+icon_width+4 ,icon_height+4);
MoveTo(memhdc,x_offset+1 ,0);
LineTo(memhdc,x_offset+icon_width+4 ,0);
MoveTo(memhdc,x_offset+1 ,icon_height+4);
LineTo(memhdc,x_offset+icon_width+4 ,icon_height+4);
SelectObject(memhdc,hpHighlight); // draw highlights
MoveTo(memhdc,x_offset+1 ,1);
LineTo(memhdc,x_offset+icon_width+3 ,1);
MoveTo(memhdc,x_offset+1 ,2);
LineTo(memhdc,x_offset+1 ,icon_height+3);
SelectObject(memhdc,hpShadow); // draw shadows
MoveTo(memhdc,x_offset+icon_width+2 ,2);
LineTo(memhdc,x_offset+icon_width+2 ,icon_height+4);
MoveTo(memhdc,x_offset+icon_width+3 ,1);
LineTo(memhdc,x_offset+icon_width+3 ,icon_height+4);
MoveTo(memhdc,x_offset+2 ,icon_height+2);
LineTo(memhdc,x_offset+icon_width+2 ,icon_height+2);
MoveTo(memhdc,x_offset+1 ,icon_height+3);
LineTo(memhdc,x_offset+icon_width+2 ,icon_height+3);
}
}
// now do 'down' bitmap
SelectObject(memhdc,hbmDown);
SelectObject(memhdc,hpFace);
Rectangle(memhdc,0,0,width,height); // faces, down map
{ // button edges, down map
int f_ofset,x_offset,x_size,y_size;
for(f_ofset=0,x_offset=0;f_ofset<actual_buttons;f_ofset++,x_offset+=(5+icon_width)){
int shrinkage=(icon_width*2)/10,oldstretchmode=SetStretchBltMode(memhdc,STRETCH_DELETESCANS);
{ // get AND data
HBITMAP x=gf.get_fill_item_and_bitmap(f_ofset,x_size,y_size);
if(x!=NULL){
x=SelectObject(icondc,x); // save old one...
StretchBlt(memhdc,x_offset+2+shrinkage,2+shrinkage,icon_width-shrinkage,icon_height-shrinkage,icondc,0,0,x_size,y_size,SRCAND);
x=SelectObject(icondc,x); // get new one back
DeleteObject(x); // and delete it
}
}
{ // get XOR data
HBITMAP x=gf.get_fill_item_xor_bitmap(f_ofset,x_size,y_size);
if(x!=NULL){
x=SelectObject(icondc,x); // save old one...
StretchBlt(memhdc,x_offset+2+shrinkage,2+shrinkage,icon_width-shrinkage,icon_height-shrinkage,icondc,0,0,x_size,y_size,SRCINVERT);
x=SelectObject(icondc,x); // get new one back
DeleteObject(x); // and delete it
}
}
SetStretchBltMode(memhdc,oldstretchmode);
SelectObject(memhdc,hpBlack); // draw black lines
MoveTo(memhdc,x_offset ,1);
LineTo(memhdc,x_offset ,icon_height+4);
MoveTo(memhdc,x_offset+icon_width+4 ,1);
LineTo(memhdc,x_offset+icon_width+4 ,icon_height+4);
MoveTo(memhdc,x_offset+1 ,0);
LineTo(memhdc,x_offset+icon_width+4 ,0);
MoveTo(memhdc,x_offset+1 ,icon_height+4);
LineTo(memhdc,x_offset+icon_width+4 ,icon_height+4);
SelectObject(memhdc,hpShadow); // draw shadows
MoveTo(memhdc,x_offset+1 ,1);
LineTo(memhdc,x_offset+icon_width+4 ,1);
MoveTo(memhdc,x_offset+1 ,2);
LineTo(memhdc,x_offset+1 ,icon_height+4);
MoveTo(memhdc,x_offset+2 ,2);
LineTo(memhdc,x_offset+icon_width+4 ,2);
MoveTo(memhdc,x_offset+2 ,3);
LineTo(memhdc,x_offset+2 ,icon_height+4);
}
}
retval=1;
bailout:
if(icondc!=NULL)DeleteDC(icondc);
if(hpShadow!=NULL)SelectObject(memhdc,hpOld);
if(hpShadow !=NULL)DeleteObject(hpShadow );
if(hpHighlight!=NULL)DeleteObject(hpHighlight);
if(hpFace !=NULL)DeleteObject(hpFace );
if(hbrFace!=NULL){
SelectObject(memhdc,hbrOld);
DeleteObject(hbrFace);
}
if(memhdc!=NULL){
SelectObject(memhdc,hbmOld);
DeleteDC(memhdc);
}
if(hdc!=NULL)DeleteDC(hdc);
return retval;
}
int button_mouse_is_in(LONG lParam){
if(actual_buttons==0||bitmap_width==0)return -1;
int x=(int)LOWORD(lParam);
int y=(int)HIWORD(lParam);
if(y<0||y>=bitmap_height||x<0||x>=bitmap_width)return -1;
x/=BUTTON_WIDTH;
if(x>=actual_buttons)return -1;
return x;
}
void restore_mouse_normalcy(void){
if(mouse_down){
ReleaseCapture();
mouse_down=0;
SetWindowText(main_hwnd,WindowTitle);
InvalidateRect(main_hwnd,NULL,FALSE);
UpdateWindow(main_hwnd);
}
}
void get_right_bitmap(HDC hdc){
/*
draws appropriate bitmap into hdc if necessary, a memory DC
the right-sized bitmap is already there
*/
HDC hdc_source;
HBITMAP hbmOld;
if(!mouse_down||mouse_button_number==-1||
!bitmap_width||!actual_buttons||
(0==(hdc_source=CreateCompatibleDC(hdc)))){
// just poke in the 'Up' bitmap
SelectObject(hdc,hbmUp);
}
else{
int left_edge=mouse_button_number*BUTTON_WIDTH;
// first draw all 'up' buttons
hbmOld=SelectObject(hdc_source,hbmUp);
BitBlt(hdc,0,0,bitmap_width,bitmap_height,hdc_source,0,0,SRCCOPY);
// now poke in the single 'down' button
SelectObject(hdc_source,hbmDown);
BitBlt(hdc,left_edge,0,BUTTON_WIDTH,bitmap_height,hdc_source,left_edge,0,SRCCOPY);
SelectObject(hdc_source,hbmOld);
DeleteDC(hdc_source);
}
}
#ifdef FAKE_LAUNCHES
char *show_exe_data(int offset){
static char buf[300];
wsprintf(buf,"Name \"%s\"\nExecutable \"%s\"\nDefault Directory \"%s\"\n%s minimized",
gf.get_item_name(offset),
gf.get_command(offset),
gf.get_item_path(offset),
(LPSTR)(gf.is_item_iconized(offset)?"Runs":"Does not run"));
return buf;
}
#else
void start_program(int offset){
// launch the program, minimized if appropriate
// report failures to the user
UINT retval=0;
if(winver>=0x30A){
#ifdef SHOW_LAUNCHDATA
errscreen<<"Ready to start\nget_item_command()=\""<<gf.get_item_command(offset);
errscreen<<"\"\nget_item_parameters()=\""<<gf.get_item_parameters(offset);
errscreen<<"\"\nget_item_default_dir()=\""<<gf.get_item_default_dir(offset);
errscreen<<"\"\nitem is"<<(gf.is_item_iconized(offset)?"":" not")<<" iconized";
errscreen.show();
#endif
UINT old_error_mode=SetErrorMode(SEM_NOOPENFILEERRORBOX);
HINSTANCE s=LoadLibrary("SHELL.DLL");
HINSTANCE (WINAPI*lpShellExecute)(HWND,LPCSTR,LPCSTR,LPCSTR,LPCSTR,int);
if(s>=HINSTANCE_ERROR)lpShellExecute=(HINSTANCE(WINAPI*)(HWND,LPCSTR,LPCSTR,LPCSTR,LPCSTR,int))GetProcAddress(s,"ShellExecute");
if(s>=HINSTANCE_ERROR&&lpShellExecute!=NULL){
retval=(*lpShellExecute)(main_hwnd,NULL,
gf.get_item_command(offset),gf.get_item_parameters(offset),
gf.get_item_default_dir(offset),
gf.is_item_iconized(offset)?SW_SHOWMINIMIZED:SW_SHOWNORMAL);
}
if(s>=HINSTANCE_ERROR)FreeLibrary(s);
SetErrorMode(old_error_mode);
}
else{
char buffer[250],*t;
retval=2;
LPSTR from=gf.get_item_default_dir(offset);
if(from!=NULL){ // use path we stripped off originally
lstrcpy(buffer,from);
t=buffer;
while(*t)t++;
if(t[-1]!=':'&&t[-1]!='\\'){
*t++='\\';
*t=0;
}
lstrcpy(t,gf.get_item_command(offset));
retval=WinExec(buffer,gf.is_item_iconized(offset)?SW_SHOWMINNOACTIVE:SW_SHOW);
}
if(retval==2){ // use 3.1-style command if present
retval=WinExec(gf.get_item_command(offset),gf.is_item_iconized(offset)?SW_SHOWMINNOACTIVE:SW_SHOW);
}
if((retval==2)&&(gf.get_item_command(offset)!=gf.get_item_command_nopath(offset))){ // .EXE name only
retval=WinExec(gf.get_item_command_nopath(offset),gf.is_item_iconized(offset)?SW_SHOWMINNOACTIVE:SW_SHOW);
}
}
if(retval>=32)return; //success!
char *p;
switch(retval){
case 0: p="System memory shortage or corrupt executable file"; break;
case 2: p="File was not found"; break;
case 3: p="Path was not found"; break;
case 5: p="Attempt to dynamically link to a task, or sharing or network-protection error"; break;
case 6: p="Library required separate data segments for each task"; break;
case 8: p="Insufficient memory to start application"; break;
case 10: p="Application can't run on this version of Windows"; break;
case 11: p="Invalid executable file. Not a Windows application, or .EXE image error"; break;
case 12: p="Application designed for a different operating system"; break;
case 13: p="Application was designed for MS-DOS 4.0"; break;
case 14: p="Unknown executable type"; break;
case 15: p="Cannot run real-mode Windows applications"; break;
case 16: p="Can't run multiple copies of this program (non-read-only multiple data segments)"; break;
case 19: p="File must be decompressed before it is loaded"; break;
case 20: p="One of the DLLs required to run this application was corrupt or otherwise invalid"; break;
case 21: p="Application requires 32-bit extensions to Windows"; break;
default: p="Unknown error"; break;
}
errscreen<<"Could not start "<<gf.get_item_command(offset)<<"\n\n"<<p;
errscreen.show();
}
#endif